package robots;

import java.util.Timer;
import java.util.TimerTask;

import maze.Coordinate;
import maze.Direction;
import maze.Location;
import pacman.Game;
import robots.analyser.BarcodeAnalyser;
import robots.correction.VirtualRobotCorrector;
import sensors.virtualSensors.VirtualInfraredSensor;
import sensors.virtualSensors.VirtualLightSensor;
import sensors.virtualSensors.VirtualPilot;
import sensors.virtualSensors.VirtualUltrasonicSensor;
import simulation.Simulator;

public class VirtualGhost extends OwnGhost {
	
	private VirtualPilot pilot;
	
	private BarcodeAnalyserTask barcodeAnalyserTask;
	
	protected BarcodeAnalyserTask getBarcodeAnalyserTask(){
		return barcodeAnalyserTask;
	}
	public VirtualGhost(Game game, String name, Simulator sim) {
		this(game, new Location(20,20), name, sim,false);
	}
	public VirtualGhost(Game game, String name, Simulator sim,boolean randomValues) {
		this(game, new Location(20,20), name, sim,randomValues);
	}
	public VirtualGhost(Game game, Location loc, String name, Simulator sim) {
		this(game, loc, name, sim,false);
	}
	//random values in te stellen
	public VirtualGhost(Game game, Location loc, String name, Simulator sim, boolean randomValues){
		super(game, loc, name);
		isTravelling = false;
		setUltrasonicSensor(new VirtualUltrasonicSensor(this, sim,randomValues));
		setLightSensor(new VirtualLightSensor(this, sim,randomValues));
		setInfraredSensor(new VirtualInfraredSensor(this, sim,randomValues));
		VirtualRobotCorrector corr = new VirtualRobotCorrector(this);
		corr.lowerCorrectionLimit=20;
		corr.upperCorrectionLimit=20;
		corr.extraCorrection=0;
				
		setRobotCorrector(corr);
		pilot= new VirtualPilot(this, sim,randomValues);
	}
	Timer timer = new Timer();
	protected void scheduleBarcodeAnalyserTask(){
		
		barcodeAnalyserTask = new BarcodeAnalyserTask();
		int barcodeUpdatePeriod = 5;
		timer.schedule(barcodeAnalyserTask, 0, barcodeUpdatePeriod);
	}

	@Override
	public void travel(int distance, boolean correction, boolean interrupt) {
		boolean interrupted = false;
		if(interrupt){
			int currentSensorRotation=getSensorRotation();
			resetSensorMotor();
			Coordinate currentCoordinate = this.getMaze().getCoordinateOfLocation(getLocation());
			boolean otherRobotInDirection = OtherRobotInDirection(currentCoordinate);
			int distanceTravelled=pilot.travelWithUltrasonicInterrupt(distance, 10);
			rotateSensorMotor(currentSensorRotation);
			if(distanceTravelled<distance){
				if(distance > 45)
					pilot.simulateTravel(15-distanceTravelled);
				else
					pilot.simulateTravel(-distanceTravelled);
				if(!otherRobotInDirection)
					this.getMaze().write(currentCoordinate.x,currentCoordinate.y,generateDirection(getRotation()) , (char)1, true);
				interrupted=true;
			}
		}
		// is veranderd van positie en dit moet aangepast worden in de location van de ghost
		if(!interrupted){
			if(correction)
				// het is een correctiemethode van de simulator, deze mag niet aangepast worden in de ghost.
				pilot.simulateTravel(distance);
			else{
				double rotRad= Math.toRadians(getRotation());
//				double newX= getLocation().getX()+Math.cos(rotRad)*distance;
//				double newY= getLocation().getY()+Math.sin(rotRad)*distance;
				double newX= getLocation().getX()+Math.cos(rotRad)*40;
				double newY= getLocation().getY()+Math.sin(rotRad)*40;
				this.setLocation(new Location(newX, newY));
				protocolSender.sendPOSITION();
			}
		}

	}
	private boolean OtherRobotInDirection(Coordinate current){
		Direction direction = generateDirection(getRotation());
		Coordinate coord = Coordinate.getCoordinateInDirection(current, direction);
		for(int i=0; i<this.getGhostPositions().length;i++){
			Coordinate coordOther = this.getGhostPositions()[i];
			if(coord.equals(coordOther))
				return true;
		}
		return false;
			
	}
	@Override
	public void rotate(int degrees, boolean correction) {
		pilot.simulateRotation(degrees);
		if(!correction)
			setRotation((getRotation()+degrees)%360);
	}
	
	/**
	 * Invokes the Update() method of the BarcodeAnalyser every period when scheduled.
	 * Takes appropriate action when a barcode is detected.
	 */
	class BarcodeAnalyserTask extends TimerTask {
		
		public BarcodeAnalyser barcodeAnalyser;
		
		public BarcodeAnalyserTask(){
			barcodeAnalyser = new BarcodeAnalyser();
			barcodeAnalyser.whiteMargin = 80;
			barcodeAnalyser.blackMargin = 20;
			barcodeAnalyser.SetBrownValue(127);
		}
		@Override
		public void run() {
			if (terminated) this.cancel();
			if (!isTravelling) //virtuele enkel
				return;
			String bc = "";
				bc = barcodeAnalyser.Update(getLightSensor().readValue());
			if (!bc.equals("")) {
				System.out.println("Barcode detected: " + bc);
				sendAndAddBarcode(bc, getLocation());
			}
		}
	}

	

	
	protected void registerPacman(){
		int directionIR = getInfraredSensor().getDirection();
	
		if(directionIR==5){
			Coordinate pacman=Coordinate.getCoordinateInDirection(getMaze().getCoordinateOfLocation(getLocation()), generateDirection());
			if(pacman!=null){
				setCoordinatePacman(pacman);
				protocolSender.sendPACMAN(pacman);

			}
		} 
		if(directionIR==0 && hasFoundPacman() && Coordinate.getCoordinateInDirection(getMaze().getCoordinateOfLocation(getLocation()), generateDirection()).equals(getCoordinatePacman())){
			foundPacman(false);
			currentStrategy.unsetPacman();
			defaultStrategy.unsetPacman();
			secondaryStrategy.unsetPacman();
			
		}
	}

	@Override
	public void rotateSensorMotor(int degrees) {
		setSensorRotation(getSensorRotation() + degrees);
	}

	@Override
	public void setSpeed(int speed) {
		pilot.setSpeed(speed);
	}
	@Override
	protected void victory() {
		// TODO Auto-generated method stub
		
	}
}
